package self.vector.ding.dao.mybatis.generator.plugin;

import static org.mybatis.generator.internal.util.messages.Messages.getString;

import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.Interface;
import org.mybatis.generator.api.dom.java.JavaVisibility;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.Document;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.internal.util.StringUtility;

public class SelectByColumnPlugin extends PluginAdapter {
	
	private final String MethodName = "selectByColumn";
	private final String Param_ColumnName = "columnName";
	private final String Param_ColumnValue = "columnValue";

	public boolean validate(List<String> warnings) {
		return true;
	}

	public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass,
			IntrospectedTable introspectedTable) {
		generateMethod(interfaze, topLevelClass, introspectedTable, false);
		if (introspectedTable.getRules().generateResultMapWithBLOBs()) {
			generateMethod(interfaze, topLevelClass, introspectedTable, true);
		}

		return true;
	}

	public void generateMethod(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable,
			boolean withBlobs) {
		Set<FullyQualifiedJavaType> importedTypes = new TreeSet<FullyQualifiedJavaType>();
		FullyQualifiedJavaType type = new FullyQualifiedJavaType(introspectedTable.getExampleType());
		importedTypes.add(type);
		importedTypes.add(FullyQualifiedJavaType.getStringInstance());
		importedTypes.add(FullyQualifiedJavaType.getNewListInstance());

		Method method = new Method();
		method.setVisibility(JavaVisibility.PUBLIC);

		FullyQualifiedJavaType returnType = FullyQualifiedJavaType.getNewListInstance();
		FullyQualifiedJavaType listType = null;

		if (withBlobs) {
			method.setName(MethodName + "WithBLOBs");
			if (introspectedTable.getRules().generateRecordWithBLOBsClass()) {
	            listType = new FullyQualifiedJavaType(introspectedTable
	                    .getRecordWithBLOBsType());
	        } else {
	            // the blob fields must be rolled up into the base class
	            listType = new FullyQualifiedJavaType(introspectedTable
	                    .getBaseRecordType());
	        }
		} else {
			method.setName(MethodName);
			if (introspectedTable.getRules().generateBaseRecordClass()) {
	            listType = new FullyQualifiedJavaType(introspectedTable
	                    .getBaseRecordType());
	        } else if (introspectedTable.getRules().generatePrimaryKeyClass()) {
	            listType = new FullyQualifiedJavaType(introspectedTable
	                    .getPrimaryKeyType());
	        } else {
	            throw new RuntimeException(getString("RuntimeError.12")); //$NON-NLS-1$
	        }
		}
		importedTypes.add(listType);
		returnType.addTypeArgument(listType);
		method.setReturnType(returnType);
		
		method.addParameter(new Parameter(FullyQualifiedJavaType.getStringInstance(), Param_ColumnName,
				"@Param(\"" + Param_ColumnName + "\")"));
		method.addParameter(new Parameter(FullyQualifiedJavaType.getObjectInstance(), Param_ColumnValue,
				"@Param(\"" + Param_ColumnValue + "\")"));

		this.context.getCommentGenerator().addGeneralMethodComment(method, introspectedTable);

		interfaze.addMethod(method);
	}

	public boolean sqlMapDocumentGenerated(Document document, IntrospectedTable introspectedTable) {
		generateXmlDocument(document, introspectedTable, false);
		if (introspectedTable.getRules().generateResultMapWithBLOBs()) {
			generateXmlDocument(document, introspectedTable, true);
		}

		return true;
	}

	public void generateXmlDocument(Document document, IntrospectedTable introspectedTable, boolean withBlobs) {
		XmlElement answer = new XmlElement("select");
		String methodName = MethodName;
		String resultMap = introspectedTable.getBaseResultMapId();
		if (withBlobs) {
			methodName = methodName + "WithBLOBs";
			resultMap = introspectedTable.getResultMapWithBLOBsId();
		}
		answer.addAttribute(new Attribute("id", methodName));
		answer.addAttribute(new Attribute("resultMap", resultMap));
		answer.addAttribute(new Attribute("parameterType", "map"));

		this.context.getCommentGenerator().addComment(answer);

		answer.addElement(new TextElement("select distinct"));
//		XmlElement ifElement = new XmlElement("if");
//		ifElement.addAttribute(new Attribute("test", "distinct"));
//		ifElement.addElement(new TextElement("distinct"));
//		answer.addElement(ifElement);

		StringBuilder sb = new StringBuilder();

		if (StringUtility.stringHasValue(introspectedTable.getSelectByExampleQueryId())) {
			sb.append('\'');
			sb.append(introspectedTable.getSelectByExampleQueryId());
			sb.append("' as QUERYID,");
			answer.addElement(new TextElement(sb.toString()));
		}

		answer.addElement(getBaseColumnListElement(introspectedTable));
		if (withBlobs) {
			answer.addElement(new TextElement(","));
			answer.addElement(getBlobColumnListElement(introspectedTable));
		}

		sb.setLength(0);
		sb.append("from ");
		sb.append(introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime());
		sb.append(" where ");
		answer.addElement(new TextElement(sb.toString()));
		XmlElement chooseElement = new XmlElement("choose");
		XmlElement whenElement = new XmlElement("when");
		whenElement.addAttribute(new Attribute("test", "columnValue == null"));
		whenElement.addElement(new TextElement("${columnName} is null"));
		chooseElement.addElement(whenElement);
		whenElement = new XmlElement("when");
		whenElement.addAttribute(new Attribute("test", "columnValue != null"));
		whenElement.addElement(new TextElement("${columnName} = #{columnValue}"));
		chooseElement.addElement(whenElement);
		answer.addElement(chooseElement);

		XmlElement parentElement = document.getRootElement();
		parentElement.addElement(answer);
	}

	protected XmlElement getBaseColumnListElement(IntrospectedTable introspectedTable) {
		XmlElement answer = new XmlElement("include");
		answer.addAttribute(new Attribute("refid", introspectedTable.getBaseColumnListId()));
		return answer;
	}

	protected XmlElement getBlobColumnListElement(IntrospectedTable introspectedTable) {
		XmlElement answer = new XmlElement("include");
		answer.addAttribute(new Attribute("refid", introspectedTable.getBlobColumnListId()));
		return answer;
	}
}